package com.feige.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.feige.constant.Constants;
import com.feige.dao.UserMapper;
import com.feige.openfeigh.ClazzService;
import com.feige.pojo.Clazz;
import com.feige.pojo.User;
import com.feige.pojo.dto.ForgetPwd;
import com.feige.pojo.dto.FriendDto;
import com.feige.pojo.dto.PwdDto;
import com.feige.pojo.vo.ChatUserVo;
import com.feige.result.AjaxResult;
import com.feige.result.R;
import com.feige.service.UserService;
import com.feige.utils.redis.RedisUtils;
import com.feige.utils.validate.ValidateEmail;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author feige
 * @since 2020-11-20
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private ClazzService clazzService;

    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Resource
    private ValidateEmail validateEmail;

    @Override
    public List<ChatUserVo> getChatUser(Integer pageNum, String userId) {
        HashMap<String, Object> map = new HashMap<>(10);
        map.put("pageNum",(pageNum - 1) * Constants.CHAT_USER_PAGE_SIZE);
        map.put("userId",userId);
        map.put("pageSize", Constants.CHAT_USER_PAGE_SIZE);
        List<ChatUserVo> chatUserVos = this.baseMapper.getChatUser(map);
        return chatUserVos.stream().peek(chatUserVo -> {
            if (StrUtil.isNotBlank(chatUserVo.getAvatar())){
                chatUserVo.setAvatarType(1);
            }else {
                if (StrUtil.isBlank(chatUserVo.getName())){
                    chatUserVo.setName("课");
                }
                chatUserVo.setAvatarType(3);
            }
        }).collect(Collectors.toList());
    }

    @Override
    public List<ChatUserVo> getChatUserByName(String name,String userId) {
        List<ChatUserVo> chatUserVos = this.baseMapper.getChatUserByName(name,userId);
        return chatUserVos.stream().peek(chatUserVo -> {
            if (StrUtil.isNotBlank(chatUserVo.getAvatar())){
                chatUserVo.setAvatarType(1);
            }else {
                if (StrUtil.isBlank(chatUserVo.getName())){
                    chatUserVo.setName("课");
                }
                chatUserVo.setAvatarType(3);
            }
        }).collect(Collectors.toList());
    }

    @Override
    public int getChatUserTotal(String userId) {
        return this.baseMapper.getChatUserTotal(userId);
    }

    @Override
    public boolean addFriend(FriendDto friendDto) {
        int a = 2;
        if (this.baseMapper.existsFriend(friendDto) <= 0){
            a = this.baseMapper.addFriend(friendDto);
        }
        return a > 1 ;
    }

    @Override
    public boolean deleteFriend(FriendDto friendDto) {
        int a = 2;
        if (this.baseMapper.existsFriend(friendDto) > 0){
            a = this.baseMapper.deleteFriend(friendDto);
        }
        return a > 1 ;
    }

    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult jointClazz(String userId, String clazzId) {
        R<Clazz> clazzR = clazzService.selectById(clazzId);
        Clazz clazz = null;
        if (clazzR.getCode() == 200){
            clazz = clazzR.getData();
        }
        assert clazz != null;
        if (!clazz.getUserId().equals(userId)){
            if (clazz.getJoinCount() + 1 <= clazz.getMaxJoinCount()){
                User user = this.getById(userId);
                if (user != null && "0".equals(user.getClazzId())){
                    User user1 = new User();
                    user1.setClazzId(clazzId);
                    user1.setId(userId);
                    boolean update = this.updateById(user1);
                    if (update) {
                        // 班级已加入人数加一
                        R<Clazz> r = clazzService.incrementBy(clazzId);
                        if (r.getCode() == 200){
                            return AjaxResult.error(5050,"服务调用失败！");
                        }
                        String key = Constants.LOGIN_USER_KEY + userId;
                        User securityUser = (User) redisUtils.get(key);
                        if (ObjectUtil.isNotEmpty(securityUser)){
                            securityUser.setClazzId(clazzId);
                            redisUtils.set(key,securityUser);
                        }else {
                            return AjaxResult.error();
                        }
                        return AjaxResult.success();
                    }else {
                        return AjaxResult.error();
                    }
                }else {
                    return AjaxResult.error(5000,"你已经加入班级，请先退出后再加入");
                }
            }else {
                return AjaxResult.error(5000,"该班级人数已达上限！");
            }
        }else {
            return AjaxResult.error(5000,"你是该班级的创建者！");
        }


    }

    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult exitClazz(String userId,String clazzId) {
        User user1 = this.getById(userId);
        if (user1 != null && user1.getClazzId().equals(clazzId)){
            User user = new User();
            user.setClazzId("0");
            user.setId(userId);
            boolean update = this.updateById(user);
            R<Clazz> r = clazzService.decrementBy(clazzId);
            if (r.getCode() == 200){
                return AjaxResult.error(5050,"服务调用失败！");
            }
            if (update) {
                String key = Constants.LOGIN_USER_KEY + userId;
                User securityUser = (User) redisUtils.get(key);
                if (ObjectUtil.isNotEmpty(securityUser)){
                    securityUser.setClazzId("0");
                    redisUtils.set(key,securityUser);
                }
                return AjaxResult.success();
            }else {
                return AjaxResult.error();
            }
        }else {
            return AjaxResult.error(5000,"踢出失败，未加入该班级！");
        }
    }

    @Override
    public List<Object> getUserIdsByClazzId(String clazzId, String userId) {
        String key = Constants.GROUP_USER_ID_KEY + clazzId;
        List<Object> userIds = redisUtils.lGet(key, 0, -1);
        List<Object> list = null;
        // 如果Redis中存在就不查询数据库
        if (userIds != null && !userIds.isEmpty()){
            list = userIds;
        }else {
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper
                    .select("id")
                    .eq("clazz_id", clazzId);
            list = this.list(wrapper).stream().map(User::getId).collect(Collectors.toList());
            if (list != null && !list.isEmpty()){
                // 把课程创建者也加入到列表
                list.add(userId);
                // 设置随机过期时间
                int randomInt = RandomUtil.randomInt(1,10);
                // 把查询数据库的结果存入Redis，以便于下次获取
                redisUtils.lSet(key,list,randomInt * 10L * 60L * 60L);
            }
        }
        return list;
    }

    @Override
    public AjaxResult changePwd(String userId, PwdDto pwdDto) {
        User user = this.getById(userId);
        if (user != null && bCryptPasswordEncoder.matches(pwdDto.getOldPwd(), user.getPassword())){
            User user1 = new User();
            user1.setId(userId);
            user1.setPassword(bCryptPasswordEncoder.encode(pwdDto.getNewPwd()));
            boolean update = this.updateById(user1);
            if (update) {
                return AjaxResult.success();
            } else {
                return AjaxResult.error();
            }
        }
        return AjaxResult.error(5000,"原密码和数据库不匹配，修改失败！");
    }

    @Override
    public AjaxResult forgetPwd(ForgetPwd forgetPwd) {
        // 判断验证码是否正确
        validateEmail.validateEmail(forgetPwd.getEmail(),forgetPwd.getCode());
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper
                .select("id")
                .eq("email",forgetPwd.getEmail());
        User user = this.getOne(wrapper);
        if (user != null && StrUtil.isNotBlank(user.getId())){
            User user1 = new User();
            user1.setId(user.getId());
            user1.setPassword(bCryptPasswordEncoder.encode(forgetPwd.getNewPwd()));
            boolean update = this.updateById(user1);
            if (update) {
                return AjaxResult.success();
            } else {
                return AjaxResult.error();
            }
        }
        return AjaxResult.error(5000,"该邮箱未注册，修改失败！");
    }

    @Override
    public String checkEmailAuthorize(String email) {
        return this.baseMapper.checkEmailAuthorize(email);
    }


}
